package de.tabuma.lib.webservice.response;

import javax.servlet.http.*;

import java.lang.reflect.*;
import java.util.*;
import java.util.logging.*;

import de.tabuma.webservice.*;

/**
 * @author $Author: alefen $
 * @version $Revision: 1.1.1.1.6.1 $
 * @since $Date: 2010/01/13 10:15:58 $
 */
public class ResponseFacade {
    
    private static final Logger log = Logger.getLogger(ResponseFacade.class.getName());
    
    public static final String createResponse(HttpServletRequest request, Hashtable<String,Class> methodTable, String targetNamespace) {
        String str = "";
        String soapAction = request.getHeader("SOAPAction");
        soapAction = soapAction.replaceAll("\"", "");
        Enumeration<String> keys = methodTable.keys();
        //Loooking for the right method to be fullfilled
        while(keys.hasMoreElements()) {
            String key = keys.nextElement();
            Class clazz = methodTable.get(key);
            for(int i=0;i<clazz.getDeclaredMethods().length;i++) {
                Method method = clazz.getDeclaredMethods()[i];
                if(soapAction.equals(key+"_"+method.getName())) {
                    str += handleRequest(request,key, method, targetNamespace);
                }
            }
        }
        return str;
    }
    
    public static final String handleRequest(HttpServletRequest request, String name, Method method, String targetNamespace) {
        String str = "";
        String prefix = "";
        try {

            XmlHandler xmlHandler = new XmlHandler(request.getInputStream(), name, method, targetNamespace);
            prefix = xmlHandler.prefix;
            int j=0;
            List objectList = new ArrayList();
            for(int i=0;i<xmlHandler.getMethodParameter().size();i++) {
                Class clazz = xmlHandler.getMethodParameter().get(i);
                log.warning(""+clazz);
                String value = xmlHandler.getValueParameter().get(j);
                log.warning(value);
                Object obj = loadSimpleDatatype(clazz, value);
                if(obj==null) {
                    obj = clazz.newInstance();
                    for(int k=0;k<clazz.getDeclaredFields().length;k++) {
                        Field myField = clazz.getDeclaredFields()[k];
                        if(myField.getName().indexOf("jdo")==-1 && myField.getName().toLowerCase().indexOf("serialversion")==-1) {
                            j++;
                            value = xmlHandler.getValueParameter().get(j);
                            if(value!=null) {
                                if(!value.equals("null")) {
                                Object obj1 = loadSimpleDatatype(myField.getType(), value);
                                    if(obj1!=null) {
                                        String methodName = ObjectMethods.getSetter(myField.getName());
                                        obj.getClass().getMethod(methodName, myField.getType()).invoke(obj, obj1);
                                    }
                                }
                            }
                        }
                    }
                    objectList.add(obj);
                    j++;
                }
                else {
                    objectList.add(obj);
                    j++;
                }
            }
            Object objList[] = null;
            if(objectList.size()>0) {
                objList = new Object[objectList.size()];
                for(int i=0;i<objList.length;i++) {
                    objList[i] = objectList.get(i);
                }
            }
            if(method.getReturnType().getName().equals("void")) {
                method.invoke(null, objList);
            }
            else {
                Object returnValue = method.invoke(null, objList);
                str = getResponse(returnValue, name, method, xmlHandler.prefix, targetNamespace);
            }
        }
        catch(InvocationTargetException e) {
            Throwable e1 = e.getTargetException();
            str = "";
            str += printException(e1,name, method, prefix, targetNamespace);
            log.warning(str);
        }
        catch(Exception e) {
            str += printException(e,name, method, prefix, targetNamespace);
            log.warning(str);
        }
        return str;
    }
    
    public static final Object loadSimpleDatatype(Class clazz, String value) {
        try {
            if(clazz==java.lang.String.class) {
                return value;
            }
            if(clazz.isPrimitive()) {
                if(clazz.getSimpleName().equals("int")) {
                    return Integer.valueOf(value);
                }
                if(clazz.getSimpleName().equals("long")) {
                    return Long.valueOf(value);
                }
                if(clazz.getSimpleName().equals("double")) {
                    return Double.valueOf(value);
                }
                if(clazz.getSimpleName().equals("boolean")) {
                    return Boolean.valueOf(value);
                }
            }
            if(clazz==java.lang.Integer.class) {
                return Integer.valueOf(value);
            }
            if(clazz==java.lang.Double.class) {
                return Double.valueOf(value);
            }
            if(clazz==java.lang.Long.class) {
                return Long.valueOf(value);
            }
            if(clazz==java.lang.Boolean.class) {
                return Boolean.valueOf(value);
            }
        }
        catch(Exception e) {

        }
        return null;
    }
    
    public static final String getResponse(Object responseObject,String name, Method method, String prefix, String targetNamespace) throws Exception {
        String str = "";
        str += "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:"+prefix+"=\""+targetNamespace+"\">\n";
        str += "<soapenv:Header/>\n";
        str += "<soapenv:Body>\n";
        str += "<"+prefix+":"+name+"_"+method.getName()+">\n";
        str += "<"+prefix+":Response_"+name+"_"+method.getName()+">\n";
        Class clazz = method.getReturnType();
        //clazz is simple typ
        boolean set = false;
        if(clazz.isPrimitive()) {
            if(clazz.getSimpleName().equals("int")) {
                str += "<int>"+responseObject+"</int>\n";
                set = true;
            }
            if(clazz.getSimpleName().equals("long")) {
                str += "<long>"+responseObject+"</long>\n";
                set = true;
            }
            if(clazz.getSimpleName().equals("double")) {
                str += "<double>"+responseObject+"</double>\n";
                set = true;
            }
        }
        //class is String
        if(clazz==String.class) {
            str += "<string>"+responseObject+"</string>\n";
            set = true;
        }

        //clazz is list
        if(clazz==List.class) {
            List list = (List)responseObject;
            for(int i=0;i<list.size();i++) {
                Object obj1 = list.get(i);
                str += "<"+obj1.getClass().getSimpleName()+">\n";
                str += print(obj1);
                str += "</"+obj1.getClass().getSimpleName()+">\n";
            }
            set = true;
        }

        //clazz is object
        if(!set) {
            str += print(responseObject);
        }

        str += "</"+prefix+":Response_"+name+"_"+method.getName()+">\n";
        str += "</soapenv:Body>\n";
        str += "</soapenv-Envelope>\n";

        return str;
    }
    
    public static String print(Object obj) throws Exception {
        String str = "";

        for(int i=0;i<obj.getClass().getDeclaredFields().length;i++) {
            Field myField = obj.getClass().getDeclaredFields()[i];
            String fieldName = myField.getName().toLowerCase();
            if(fieldName.indexOf("jdo")==-1 && fieldName.indexOf("serialversionuid")==-1) {
                String methodName = ObjectMethods.getGetter(myField.getName());
                str += "<"+myField.getName()+">"+obj.getClass().getMethod(methodName).invoke(obj)+"</"+myField.getName()+">\n";
            }
        }
        return str;
    }
    
    public static String printException(Throwable e, String name, Method method, String prefix, String targetNamespace) {
        String str = "";
        str += "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:"+prefix+"=\""+targetNamespace+"\">\n";
        str += "<soapenv:Header/>\n";
        str += "<soapenv:Body>\n";

        String text = e.getMessage()+"\n";
        for(int i=0;i<e.getStackTrace().length;i++) {
            text += e.getStackTrace()[i]+"\n";
        }

        str += "<"+prefix+":Exception_"+name+"_"+method.getName()+">\n";
        str += "<ExceptionClass>"+e.getClass()+"</ExceptionClass>\n";
        str += "<ExceptionCause>"+e.getCause()+"</ExceptionCause>\n";
        str += "<ExceptionMessage>"+text+"</ExceptionMessage>\n";
        str += "</"+prefix+":Exception_"+name+"_"+method.getName()+">\n";
        str += "</soapenv:Body>\n";
        str += "</soapenv-Envelope>\n";
        return str;
    }
}
